package scau.osdesign;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import org.kordamp.bootstrapfx.BootstrapFX;
import scau.osdesign.model.Fork;
import scau.osdesign.model.Philosopher;
import scau.osdesign.service.DeadLockSim;
import scau.osdesign.service.NumberToNumberSim;
import scau.osdesign.service.SemControlSim;
import scau.osdesign.service.Simer;
import scau.osdesign.view.ViewArranger;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Objects;

public class LaunchMain extends Application {
    //phi
    public static ImageView phi_1;
    public static ImageView phi_2;
    public static ImageView phi_3;
    public static ImageView phi_4;
    public static ImageView phi_5;
    //fork
    public static ImageView fork_1;
    public static ImageView fork_2;
    public static ImageView fork_3;
    public static ImageView fork_4;
    public static ImageView fork_5;
    //left-or-right
    public static ImageView phi_1_left;
    public static ImageView phi_1_right;

    public static ImageView phi_2_left;
    public static ImageView phi_2_right;

    public static ImageView phi_3_left;
    public static ImageView phi_3_right;

    public static ImageView phi_4_left;
    public static ImageView phi_4_right;

    public static ImageView phi_5_left;
    public static ImageView phi_5_right;
    public static Parent root;
    public static Parent simServices;

    public static Button buttonChoiceOne;
    public static Button buttonChoiceTwo;
    public static Button buttonChoiceThree;

    public static Service<Integer> service;

    public static Philosopher[] philosophers;
    public static Fork[] forks;

    public static NumberToNumberSim numberToNumberSim;
    public static SemControlSim semControlSim;
    public static DeadLockSim deadLockSim;
    public static Simer simer;
    public static Label simTitle;

    public static Stage stageSim;
    public static Stage mainStage;

    public static Scene simScene;

    public static int choice ;

    @Override
    public void start(Stage stage) throws IOException {
        mainStage = stage;
        FXMLLoader simLoader = new FXMLLoader(LaunchMain.class.getResource("/scau/fxml/sim-view.fxml"));
        simServices = simLoader.load();
        FXMLLoader fxmlLoader = new FXMLLoader(LaunchMain.class.getResource("/scau/fxml/main-view.fxml"));
        root = fxmlLoader.load();
        Scene scene = new Scene(root, 680, 780);
        root.setId("pane");
        buttonChoiceOne = (Button) root.lookup("#button_choice_1");
        buttonChoiceTwo = (Button) root.lookup("#button_choice_2");
        buttonChoiceThree = (Button) root.lookup("#button_choice_3");

        simScene = new Scene(simServices,1280,800);
        stageSim = new Stage();
        stageSim.setScene(simScene);

        simTitle  = (Label) simServices.lookup("#sim_title");
        simTitle.setWrapText(true);

        try{
            buttonChoiceOne.getStylesheets().addAll(Objects.requireNonNull(LaunchMain.class.getResource("/scau/css/main-view.css")).toExternalForm());
            scene.getStylesheets().addAll(Objects.requireNonNull(LaunchMain.class.getResource("/scau/css/main-view.css")).toExternalForm());
        }catch (NullPointerException e){
            e.printStackTrace();
        }

        stage.setTitle("哲学家就餐问题");
        stage.setScene(scene);
        stage.setResizable(false);
        stage.show();
        buttonChoiceOne.addEventHandler(MouseEvent.MOUSE_CLICKED,
                mouseEvent -> {
                    initViewer(simServices);
                    DeadLockSimInit();
                    choice = 1;
                    stage.hide();
                    stageSim.setTitle("模拟界面");
                    simTitle.setText("当前正在模拟的是:不做任何处理的哲学家就餐问题(可能发生死锁)");
                    stageSim.show();
                }
        );
        buttonChoiceTwo.addEventHandler(MouseEvent.MOUSE_CLICKED,
                mouseEvent -> {
                    initViewer(simServices);
                    SemControlSimInit();
                    choice = 2;
                    stage.hide();
                    stageSim.setTitle("模拟界面");
                    simTitle.setText("当前正在模拟的是:以信号量限制的哲学家就餐问题(最多有四位哲学家拿起叉子)");
                    stageSim.show();
                }
        );
        buttonChoiceThree.addEventHandler(MouseEvent.MOUSE_CLICKED,
                mouseEvent -> {
                    initViewer(simServices);
                    NumberToNumberSimInit();
                    choice = 3;
                    stage.hide();
                    stageSim.setTitle("模拟界面");
                    simTitle.setText("当前正在模拟的是:基于编号的哲学家就餐问题(以编号限制其拿叉子的行为)");
                    stageSim.show();
                }
        );
    }

    public static void NumberToNumberSimInit(){
        service = new Service<>() {
            @Override
            protected Task<Integer> createTask() {
                return new Task<>() {
                    @Override
                    protected Integer call() {
                        philosophers = new Philosopher[NumberToNumberSim.PHILOSOPHER_NUMBER];
                        forks = new Fork[NumberToNumberSim.FORK_NUMBER];
                        numberToNumberSim = new NumberToNumberSim();
                        simer = numberToNumberSim;
                        numberToNumberSim.start();
                        return null;
                    }
                };
            }
        };
    }

    public static void DeadLockSimInit(){
        service = new Service<>() {
            @Override
            protected Task<Integer> createTask() {
                return new Task<>() {
                    @Override
                    protected Integer call() {
                        philosophers = new Philosopher[NumberToNumberSim.PHILOSOPHER_NUMBER];
                        forks = new Fork[NumberToNumberSim.FORK_NUMBER];
                        deadLockSim = new DeadLockSim();
                        simer = deadLockSim;
                        deadLockSim.start();
                        return null;
                    }
                };
            }
        };
    }

    public static void SemControlSimInit(){
        service = new Service<>() {
            @Override
            protected Task<Integer> createTask() {
                return new Task<>() {
                    @Override
                    protected Integer call() {
                        philosophers = new Philosopher[NumberToNumberSim.PHILOSOPHER_NUMBER];
                        forks = new Fork[NumberToNumberSim.FORK_NUMBER];
                        semControlSim = new SemControlSim();
                        simer = semControlSim;
                        semControlSim.start();
                        return null;
                    }
                };
            }
        };
    }

    public static void reStart(){
        switch (choice){
            case 1 ->{DeadLockSimInit();break;}
            case 2 ->{SemControlSimInit();break;}
            case 3 ->{NumberToNumberSimInit();break;}
        }

    }

    public static void initViewer(Parent root){
        phi_1 = (ImageView)root.lookup("#phi_1");
        phi_2 = (ImageView)root.lookup("#phi_2");
        phi_3 = (ImageView)root.lookup("#phi_3");
        phi_4 = (ImageView)root.lookup("#phi_4");
        phi_5 = (ImageView)root.lookup("#phi_5");

        fork_1 = (ImageView)root.lookup("#fork_1");
        fork_2 = (ImageView)root.lookup("#fork_2");
        fork_3 = (ImageView)root.lookup("#fork_3");
        fork_4 = (ImageView)root.lookup("#fork_4");
        fork_5 = (ImageView)root.lookup("#fork_5");

        phi_1_left = (ImageView)root.lookup("#phi_1_left");
        phi_1_right = (ImageView)root.lookup("#phi_1_right");

        phi_2_left = (ImageView)root.lookup("#phi_2_left");
        phi_2_right = (ImageView)root.lookup("#phi_2_right");

        phi_3_left = (ImageView)root.lookup("#phi_3_left");
        phi_3_right = (ImageView)root.lookup("#phi_3_right");

        phi_4_left = (ImageView)root.lookup("#phi_4_left");
        phi_4_right = (ImageView)root.lookup("#phi_4_right");

        phi_5_left = (ImageView)root.lookup("#phi_5_left");
        phi_5_right = (ImageView)root.lookup("#phi_5_right");

        phi_1_left.setVisible(false);
        phi_1_right.setVisible(false);
        phi_2_left.setVisible(false);
        phi_2_right.setVisible(false);
        phi_3_left.setVisible(false);
        phi_3_right.setVisible(false);
        phi_4_left.setVisible(false);
        phi_4_right.setVisible(false);
        phi_5_left.setVisible(false);
        phi_5_right.setVisible(false);

        fork_1.setVisible(true);
        fork_2.setVisible(true);
        fork_3.setVisible(true);
        fork_4.setVisible(true);
        fork_5.setVisible(true);
        try{
            FileInputStream imageInput;
            imageInput = new FileInputStream(ViewArranger.THINKING_IMAGE_URL);
            Image thinkingImage = new Image(imageInput);
            phi_1.setImage(thinkingImage);
            phi_2.setImage(thinkingImage);
            phi_3.setImage(thinkingImage);
            phi_4.setImage(thinkingImage);
            phi_5.setImage(thinkingImage);
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }

    }


    public static void main(String[] args) {
        launch();
    }
}